#include "zipList.h"
#include <unistd.h>
#include <stdint.h>
#define ZIP_BIG_PREVLEN 254 //如果entry文本长度超过254个字节，我们就要使用5个字节存放prevlen，其中第一个字节固定为0xFE（254）
#define ZIP_DECODE_PREVLENSIZE(ptr, prevlensize) \
    do                                           \
    {                                            \
        if ((ptr)[0] < ZIP_BIG_PREVLEN)          \
        {                                        \
            (prevlensize) = 1;                   \
        }                                        \
        else                                     \
        {                                        \
            (prevlensize) = 5;                   \
        }                                        \
    } while (0);

#define ZIP_DECODE_PREVLEN(ptr, prevlensize, prevlen)   \
    do                                                  \
    {                                                   \
        ZIP_DECODE_PREVLENSIZE(ptr, prevlensize);       \
        if ((prevlensize) == 1)                         \
        {                                               \
            (prevlensize) = ptr[0];                     \
        }                                               \
        else if ((prevlensize) == 5)                    \
        {                                               \
            memcpy(&(prevlen), ((char *)(ptr)) + 1, 4); \
        }                                               \
    } while (0);
#define ZIP_STR_MASK 0xc0
#define ZIP_STR_LEN_MASK 0x3f
#define ZIP_STR_06B (0 << 6)
#define ZIP_STR_14B (1 << 6)
#define ZIP_STR_14B (2 << 6)

//如果是字符串类型，我们需要将其三四位置零
#define ZIP_ENTRY_ENCODING(ptr, encoding) \
    do                                    \
    {                                     \
        (encoding) = (ptr)[0];            \
        if ((encoding) < ZIP_STR_MASK)    \
            (encoding) &= ZIP_STR_MASK;   \
    } while (0);
#define ZIP_INT_8B 0xfe
#define ZIP_INT_16B (0xc0 | 0 << 4)
#define ZIP_INT_32B (0xc0 | 1 << 4)
#define ZIP_INT_64B (0xc0 | 2 << 4)
#define ZIP_INT_24B (0xc0 | 3 << 4)
#define ZIP_INT_IMM_MIN 0xf1 /* 11110001 */
#define ZIP_INT_IMM_MAX 0xfd /* 11111101 */
unsigned int zipIntSize(unsigned char encoding)
{
    switch (encoding)
    {
    case ZIP_INT_8B:
        return 1;
    case ZIP_INT_16B:
        return 2;
    case ZIP_INT_24B:
        return 3;
    case ZIP_INT_32B:
        return 4;
    case ZIP_INT_64B:
        return 8;
    }
    if (encoding >= ZIP_INT_IMM_MIN && encoding <= ZIP_INT_IMM_MAX)
    {
        return 0;
    }
    exit(-1);
}

#define ZIP_DECODE_LENGTH(ptr, encoding, lensize, len)                 \
    do                                                                 \
    {                                                                  \
        ZIP_ENTRY_ENCODING((ptr), (encoding));                         \
        if ((encoding) < ZIP_STR_MASK)                                 \
        {                                                              \
            if ((encoding) == ZIP_STR_06B)                             \
            {                                                          \
                (lensize) = 1;                                         \
                (len) = (ptr)[0] & ZIP_STR_LEN_MASK;                   \
            }                                                          \
            else if ((encoding) == ZIP_STR_14B)                        \
            {                                                          \
                (lensize) = 2;                                         \
                (len) = ((ptr)[0] & ZIP_STR_LEN_MASK) << 8 | (ptr)[1]; \
            }                                                          \
            else if ((encoding) == ZIP_STR_14B)                        \
            {                                                          \
                (lensize) = 5;                                         \
                (len) = ((ptr)[1] << 24) |                             \
                        ((ptr)[2] << 16) |                             \
                        ((ptr)[3] << 8) |                              \
                        ((ptr)[4]);                                    \
            }                                                          \
            else                                                       \
            {                                                          \
                exit(-1);                                              \
            }                                                          \
        }                                                              \
        else                                                           \
        {                                                              \
            (lensize) = 1;                                             \
            (len) = zipIntSize(encoding);                              \
        }                                                              \
    } while (0);

void zipEntry(unsigned char *p, zlentry *e)
{
    ZIP_DECODE_PREVLEN(p, e->prevrawlensize, e->prevrawlen);
    ZIP_DECODE_LENGTH(p, e->encoding, e->lensize, e->len);
    e->headersize = e->prevrawlensize + e->lensize;
    e->p = p;
}

#define ZIPLISTHEADERSIZE 10
#define ZIPLIST_BYTES(zl) (*((uint32_t *)(zl)))
#define ZIPLIST_TAIL_OFFSET(zl) (*((uint32_t *)((zl) + sizeof(uint32_t))))
#define ZIPLIST_LENGTH(zl) (*((uint16_t *)((zl) + sizeof(uint32_t) * 2)))
#define ZIPLIST_ENTRY_TAIL(zl) ((zl) + intrev32ifbe(ZIPLIST_TAIL_OFFSET(zl)))

#define ZIP_END 255 /* Special "end of ziplist" entry. */

unsigned char *ziplistNew(void)
{
    //ZIPLISTHEADERSIZE = zlbytes + zltail + zllen
    unsigned int bytes = ZIPLISTHEADERSIZE + 1;
    unsigned char *zl = malloc(bytes);
    ZIPLIST_BYTES(zl) = bytes;
    ZIPLIST_TAIL_OFFSET(zl) = ZIPLISTHEADERSIZE;
    ZIPLIST_LENGTH(zl) = 0;
    zl[bytes - 1] = ZIP_END;
    return zl;
}

unsigned int zipRawEntryLength(unsigned char *p)
{
    unsigned int prevlensize, encoding, lensize, len;
    ZIP_DECODE_PREVLENSIZE(p, prevlensize);
    ZIP_DECODE_LENGTH(p + prevlensize, encoding, lensize, len);
    return prevlensize + lensize + len;
}
int zipTryEncoding(unsigned char *entry, unsigned int entrylen, long long *v, unsigned char *encoding)
{
    long long value;
    if (entrylen >= 32 || entrylen == 0)
        return 0;
    return 0;
}
static unsigned char *__ziplistInsert(unsigned char *zl, unsigned char *p, unsigned char *s, unsigned int slen)
{
    size_t curlen = zl, reqlen;
    unsigned int prevlensize, prevlen = 0;
    size_t offset;
    int nextdiff = 0;
    unsigned char encoding = 0;
    long long value = 123456789;
    zlentry tail;
    if (p[0] != ZIP_END)
    {
        //如果插入的位置不是压缩表的尾部，那么我们可以根据它后方的元素知道数据
        ZIP_DECODE_PREVLEN(p, prevlensize, prevlen);
    }
    else
    {
        //否则我们就需要求出原尾部元素的大小
        unsigned char *ptail = ZIPLIST_ENTRY_TAIL(zl);
        if (ptail[0] != ZIP_END)
        {
            prevlen = zipRawEntryLength(ptail);
        }
    }

    //尝试将新插入的元素编码
    if (zipTryEncoding(s, slen, &value, &encoding))
    {
        //是否能够存入整数编码中
        reqlen = zipIntSize(encoding);
    }
    else
    {
        reqlen = slen;
    }
}

unsigned char *ziplistInsert(unsigned char *zl, unsigned char *p, unsigned char *s, unsigned int slen)
{
    return __ziplistInsert(zl, p, s, slen);
}